package com.ht.api.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ht.api.bean.AjaxResult;
import com.ht.api.bean.LoginBean;
import com.ht.api.bean.UserInfo;
import com.ht.api.call.ICall;
import com.ht.api.db.Db;
import com.ht.api.db.DbList;
import com.ht.api.db.exception.HtException;
import com.ht.api.db.util.RedisUtil;
import com.ht.api.util.UserUtil;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

/**
 * 通用sql查询
 * @author asq
 * @createTime 2025年1月3日 12:03:59
 */
@RestController
@RequestMapping("/sql")
public class SqlController {
	/**
	 * 通用sql查询（使用租户数据源）
	 * @param id sql表main_id
	 * @param body 接口参数
	 * @return
	 */
	@PostMapping("/{id}")
	public AjaxResult executeByTenant(@PathVariable String id, @RequestBody JSONObject body) {
		// 获取登录用户
		UserInfo loginUser = UserUtil.getLoginUser();
		long loginId = loginUser.getId();
		long tenantId = loginUser.getTenantId();
		
		return doExecute(LoginBean.createByTenant(loginId, tenantId), id, body);
	}

	/**
	 * 通用sql查询（使用系统数据源）
	 * @param id sql表main_id
	 * @param body 接口参数
	 * @return
	 */
	@PostMapping("/sys/{id}")
	public AjaxResult executeBySys(@PathVariable String id, @RequestBody JSONObject body) {
		// 获取登录用户
		UserInfo loginUser = UserUtil.getLoginUser();
		long loginId = loginUser.getId();
		
		return doExecute(LoginBean.createBySys(loginId), id, body);
	}
	
	/**
	 * 通用sql查询
	 * @param me 操作人
	 * @param id sql表main_id
	 * @param body 接口参数
	 * @return
	 */
	private AjaxResult doExecute(LoginBean me, String id, JSONObject body) {
		// 验证参数
		checkParam(body);
		
		// 查找id对应的sql
		String key = "sql:" + id;
		String sql = RedisUtil.get(key);
		if (StrUtil.isBlank(sql)) {
			throw new HtException("通用查询不存在或未编写sql语句，id:" + id);
		}
		
		// 根据前端参数处理sql并执行
		sql = replaceParam(sql, body);// 替换前端参数
		sql = filterParam(sql, body);// 去掉前端未传的参数语句
		
		// 执行最后剩下的sql
		DbList list = Db.query(me.getDataSource(), sql);
		return AjaxResult.success(list);
	}
	
	public static void main(String[] args) {
		String sql = """
		SELECT openid, COUNT(1)num FROM order_item 
		where 1=1 [and total_price>{total_price}] [and product_name like '%{product_name}%'] GROUP BY openid
				""";
		JSONArray param = JSONUtil.createArray();
		param.add(JSONUtil.createObj().set("key", "total_price").set("value", "1000"));
		JSONObject body = JSONUtil.createObj().set("param", param);
		System.err.println(body.toStringPretty());

		sql = replaceParam(sql, body);// 替换前端参数
		System.err.println(sql);
		
		sql = filterParam(sql, body);// 去掉前端未传的参数语句
		System.err.println(sql);
	}

	/**
	 * 验证参数
	 * @param body 参数对象
	 */
	private void checkParam(JSONObject body) {
		// 要求参数必须要有param字段
		if (!body.containsKey(ICall.PARAM)) {
			throw new HtException(String.format("json参数需要%s字段~", ICall.PARAM));
		}
		Object param = body.get(ICall.PARAM);
		if (!(param instanceof JSONArray)) {
			throw new HtException(String.format("%s字段必须为JSONArray类型~", ICall.PARAM));
		}
	}
	
	/**
	 * 将sql语句中的{}替换为前端参数值
	 * @param sql
	 * @param body
	 * @return
	 */
	private static String replaceParam(String sql, JSONObject body) {
	    JSONArray paramArr = body.getJSONArray("param");
	    if (paramArr == null || paramArr.isEmpty()) {
	        return sql;
	    }

	    // 将参数转为Map方便查找
	    Map<String, Object> paramMap = new HashMap<>();
	    for (int i = 0; i < paramArr.size(); i++) {
	        JSONObject param = paramArr.getJSONObject(i);
	        paramMap.put(param.getStr("key"), param.get("value"));
	    }

	    // 使用正则表达式匹配所有{变量}并直接替换
	    Pattern pattern = Pattern.compile("\\{(.+?)\\}");
	    Matcher matcher = pattern.matcher(sql);
	    StringBuffer sb = new StringBuffer();

	    while (matcher.find()) {
	        String paramName = matcher.group(1);
	        Object paramValue = paramMap.get(paramName);
	        // 直接替换为参数值（不区分类型，不做任何处理）
	        matcher.appendReplacement(sb, paramValue != null ? paramValue.toString() : matcher.group());
	    }
	    matcher.appendTail(sb);
	    return sb.toString();
	}

	/**
	 * 将sql语句中的[]过滤掉（如果前端没有传相应值的时候）
	 * @param sql
	 * @param body
	 * @return
	 */
	private static String filterParam(String sql, JSONObject body) {
	    JSONArray paramArr = body.getJSONArray("param");
	    if (paramArr == null || paramArr.isEmpty()) {
	        // 如果没有参数，移除所有中括号内容
	        return sql.replaceAll("\\[.*?\\]", "");
	    }

	    // 收集所有前端传递的参数key
	    Map<String, Boolean> paramKeys = new HashMap<>();
	    for (int i = 0; i < paramArr.size(); i++) {
	        JSONObject param = paramArr.getJSONObject(i);
	        paramKeys.put(param.getStr("key"), true);
	    }

	    // 使用正则表达式匹配所有[条件语句]
	    Pattern pattern = Pattern.compile("\\[(.*?)\\]");
	    Matcher matcher = pattern.matcher(sql);
	    StringBuffer sb = new StringBuffer();

	    while (matcher.find()) {
	        String condition = matcher.group(1);
	        // 检查条件语句中是否包含前端没有传递的参数
	        boolean shouldKeep = true;
	        
	        // 提取条件语句中的所有参数名
	        Pattern paramPattern = Pattern.compile("\\{(.+?)\\}");
	        Matcher paramMatcher = paramPattern.matcher(condition);
	        
	        while (paramMatcher.find()) {
	            String paramName = paramMatcher.group(1);
	            if (!paramKeys.containsKey(paramName)) {
	                shouldKeep = false;
	                break;
	            }
	        }
	        
	        if (shouldKeep) {
	            // 保留这个条件语句
	            matcher.appendReplacement(sb, condition);
	        } else {
	            // 移除这个条件语句
	            matcher.appendReplacement(sb, "");
	        }
	    }
	    matcher.appendTail(sb);
	    return sb.toString();
	}
}
